package me.flyray.bsin.server.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.blockchain.config.S11eProtocolProperties;
import me.flyray.bsin.blockchain.connection.BsinBlockChainEngineFactory;
import me.flyray.bsin.blockchain.enums.ChainIdentifier;
import me.flyray.bsin.blockchain.protocol.S11eProtocolService;
import me.flyray.bsin.blockchain.tds.DefaultTrustedDataSpaceConnector;
import me.flyray.bsin.blockchain.tds.TrustedDataSpaceConnector;
import me.flyray.bsin.domain.entity.*;
import me.flyray.bsin.domain.enums.DidProfileType;
import me.flyray.bsin.exception.BusinessException;
import me.flyray.bsin.facade.engine.DidProfileServiceEngine;
import me.flyray.bsin.infrastructure.mapper.ChainCoinMapper;
import me.flyray.bsin.infrastructure.mapper.DidProfileMapper;
import me.flyray.bsin.infrastructure.mapper.WalletAccountMapper;
import me.flyray.bsin.infrastructure.mapper.WalletMapper;
import me.flyray.bsin.security.contex.LoginInfoContextHelper;
import me.flyray.bsin.security.domain.LoginUser;
import me.flyray.bsin.security.enums.BizRoleType;
import me.flyray.bsin.server.utils.Pagination;
import me.flyray.bsin.utils.StringUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.shenyu.client.apache.dubbo.annotation.ShenyuDubboService;
import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
import org.apache.shenyu.client.apidocs.annotations.ApiModule;
import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@ShenyuDubboService(path = "/didProfile", timeout = 60000)
@ApiModule(value = "didProfile")
public class DidProfileServiceEngineImpl implements DidProfileServiceEngine {

    // 固定的加密盐值配置（Base64编码）
    private static final String FIXED_ENCRYPTION_SALT = "bsin-paas-os-fixed-salt-2024-secure-key-base64-encoded==";

    @Value("${bsin.oss.ipfs.gateway}")
    private String tdsUrl;
    @Autowired
    private DidProfileMapper didProfileMapper;
    @Autowired
    private S11eProtocolService s11eProtocolService;
    @Autowired
    private S11eProtocolProperties s11eConfig;
    @Autowired
    private WalletMapper walletMapper;
    @Autowired
    private WalletAccountMapper walletAccountMapper;
    @Autowired
    private ChainCoinMapper chainCoinMapper;
    @Autowired
    private BsinBlockChainEngineFactory bsinBlockChainEngineFactory;

    /**
     * 基于客户实名认证创建可信身份
     * 调用可信数据空间创建可信身份
     * @param requestMap
     */
    @ShenyuDubboClient("/create")
    @ApiDoc(desc = "create")
    @Override
    public DidProfile create(Map<String, Object> requestMap) throws Exception {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();

        String merchantNo = StringUtils.defaultIfBlank(loginUser.getMerchantNo(), loginUser.getTenantMerchantNo());

        TrustedDataSpaceConnector trustedDataSpaceClient = buildTrustedDataSpaceConnector();
        String didType = MapUtils.getString(requestMap, "type");

        String tenantId = StringUtils.defaultIfBlank(MapUtils.getString(requestMap, "tenantId"), LoginInfoContextHelper.getTenantId());

        DidProfile didProfile = new DidProfile();
        didProfile.setTenantId(tenantId);

        // 如果是个人需要验证实名信息
        if(DidProfileType.INDIVIDUAL.getCode().equals(didType)){
            // 调用第三方进行实名认证
            didProfile.setBizRoleType(BizRoleType.CUSTOMER.getCode());
            // TODO  调用crm 生成一个客户信息
            didProfile.setBizRoleTypeNo(loginUser.getCustomerNo());
        }else if (DidProfileType.BRAND.getCode().equals(didType)){
            // 如果是商户需要验证营业执照和法人信息t
            didProfile.setBizRoleType(BizRoleType.MERCHANT.getCode());
            didProfile.setBizRoleTypeNo(merchantNo);
        }else {
            throw new BusinessException("11","类型暂不支持");
        }
        requestMap.put("salt", FIXED_ENCRYPTION_SALT);
        Map<String, String> didProfileMap = trustedDataSpaceClient.createDidProfile(requestMap);

        String did = didProfileMap.get("did");
        didProfile.setDid(did);
        didProfile.setName(didProfileMap.get("name"));
        didProfile.setSymbol(didProfileMap.get("idNumber"));
        didProfile.setDidDoc(didProfileMap.get("didDocument"));
        didProfile.setDidKeyData(didProfileMap.get("didKeyData"));
        didProfile.setDescription("DID profile for " + didProfileMap.get("name"));

        // 检查DID是否已存在
        LambdaQueryWrapper<DidProfile> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DidProfile::getDid, did);
        queryWrapper.or().eq(DidProfile::getBizRoleTypeNo, loginUser.getBizRoleTypeNo());
        DidProfile existingProfile = didProfileMapper.selectOne(queryWrapper);
        if (existingProfile != null) {
            return existingProfile;
        }

        // 判断是否需要上链标识，如果上链需要基于DID进行链上铸造profile
        Boolean onChainFlag = MapUtils.getBoolean(requestMap, "onChainFlag");
        Map<String, Object> chainResult = null;
        if(onChainFlag){

            didProfile.setChainIdentifier(MapUtils.getString(requestMap, "chainIdentifier"));

            // 创建链上Profile
            requestMap.put("did", did);

            Map<String, Object> profileRequestMap =
                    prepareProfileRequest(requestMap, didProfileMap, didType, did, merchantNo);
            chainResult = s11eProtocolService.createProfile(profileRequestMap);
            
            // 处理链上创建结果
            // SDK 会自动处理费用授权和 AssetFactory 设置，并总是设置 success=true
            if (chainResult != null) {
                String profileAddress = (String) chainResult.get("profileAddress");
                String txHash = (String) chainResult.get("txHash");
                String transactionHash = (String) chainResult.get("transactionHash");
                Boolean success = (Boolean) chainResult.get("success");
                
                // SDK 总是设置 success=true，但为了健壮性仍进行检查
                if (profileAddress != null && !profileAddress.isEmpty()) {
                    didProfile.setContractAddress(profileAddress);
                    log.info("链上Profile创建成功: did={}, profileAddress={}, txHash={}", 
                            did, profileAddress, txHash != null ? txHash : transactionHash);
                } else {
                    // Profile 地址解析失败，但交易可能已提交
                    String finalTxHash = txHash != null ? txHash : transactionHash;
                    if (finalTxHash != null) {
                        log.warn("链上Profile创建交易已提交但地址解析失败: did={}, txHash={}, success={}", 
                                did, finalTxHash, success);
                        // 交易已提交，即使地址解析失败也记录交易hash
                    } else {
                        log.error("链上Profile创建失败: did={}, success={}, 未找到交易hash", did, success);
                    }
                }
            } else {
                log.error("链上Profile创建返回结果为空: did={}", did);
            }
        }

        // 保存可信数据空间用户身份信息
        didProfileMapper.insert(didProfile);
        log.info("DID档案创建成功，DID: {}, 记录ID: {}", did, didProfile.getSerialNo());
        return didProfile;
    }

    TrustedDataSpaceConnector buildTrustedDataSpaceConnector() {
        return TrustedDataSpaceConnector.builder()
                .endpointUrl(tdsUrl)
                .apiKey("your-api-key-here")
                .connectTimeout(15, TimeUnit.SECONDS)
                .readTimeout(45, TimeUnit.SECONDS)
                .maxRetries(5)
                .addCustomHeader("X-Tenant-ID", "tenant-123")
                .addCustomHeader("X-Client-Version", "1.0.0")
                .build();
    }

    Map<String, Object> prepareProfileRequest(Map<String, Object> requestMap,
                                              Map<String, String> didProfileMap,
                                              String didType,
                                              String did,
                                              String merchantNo) {
        String chainIdentifier = StringUtils.defaultIfBlank(MapUtils.getString(requestMap, "chainIdentifier"),
                ChainIdentifier.ETHEREUM.getCode());
        String chainEnv = StringUtils.defaultIfBlank(MapUtils.getString(requestMap, "chainEnv"), "test");
        if (StringUtils.isBlank(chainIdentifier)) {
            throw new BusinessException("WAAS_CHAIN_REQUIRED", "缺少链标识，无法创建链上资料");
        }
        String nativeCoin = bsinBlockChainEngineFactory.getChainNativeCoin(chainIdentifier);
        log.info("准备用链上资料，链标识:{}，链本币:{}", chainIdentifier, nativeCoin);
        ChainCoin chainNativeCoin = chainCoinMapper.selectOne(new LambdaQueryWrapper<ChainCoin>()
                .eq(ChainCoin::getChainIdentifier, chainIdentifier)
                .eq(ChainCoin::getCoin, nativeCoin));
        if (chainNativeCoin == null) {
            throw new BusinessException("WAAS_CHAIN_COIN_NOT_FOUND",
                    "链 " + chainIdentifier + " 未配置本币，请检查 waas_chain_coin 表");
        }
        WalletAccount walletAccount = findMerchantChainWallet(chainNativeCoin, merchantNo);
        String brandAddress = walletAccount.getAddress();
        String brandPrivate = walletAccount.getPrivateKey();
        if (StringUtils.isBlank(brandAddress) || StringUtils.isBlank(brandPrivate)) {
            throw new BusinessException("WAAS_BRAND_WALLET_MISSING", "品牌钱包地址或私钥为空，无法签名链上交易");
        }

        Map<String, Object> profileRequestMap = new HashMap<>();
        profileRequestMap.put("chainIdentifier", chainIdentifier);
        profileRequestMap.put("chainEnv", chainEnv);
        profileRequestMap.put("s11eCoreAddress", s11eConfig.getContracts().getS11eCore());
        profileRequestMap.put("profileType", didType);
        profileRequestMap.put("name", didProfileMap.get("name"));
        profileRequestMap.put("symbol", "SDKTB");
        profileRequestMap.put("did", did);
        profileRequestMap.put("profileNo", did);
        profileRequestMap.put("brandAddress", brandAddress);
        profileRequestMap.put("brandPrivate", brandPrivate);
        profileRequestMap.put("baseURI", s11eConfig.getBaseUri());
        profileRequestMap.put("erc6551Registry", s11eConfig.getContracts().getErc6551Registry());
        profileRequestMap.put("externalUri", "https://sdk-test.s11e.io");

        log.info("Profile链上请求：chainIdentifier={}, chainEnv={}, brandAddress={}, brandPrivate={}",
                chainIdentifier,
                chainEnv,
                maskSensitive(brandAddress, 6),
                maskSensitive(brandPrivate, 6));
        if (log.isDebugEnabled()) {
            Map<String, Object> safeProfileRequest = new HashMap<>(profileRequestMap);
            safeProfileRequest.put("brandPrivate", maskSensitive(brandPrivate, 6));
            log.debug("Profile链上请求明细: {}", safeProfileRequest);
        }
        return profileRequestMap;
    }

    private WalletAccount findMerchantChainWallet(ChainCoin chainNativeCoin, String merchantNo) {
        WalletAccount walletAccount = null;
        Wallet wallet = walletMapper.selectOne(new LambdaQueryWrapper<Wallet>()
                .eq(Wallet::getBizRoleTypeNo, merchantNo));
        if (wallet != null) {
            walletAccount = walletAccountMapper.selectOne(new LambdaQueryWrapper<WalletAccount>()
                    .eq(WalletAccount::getWalletNo, wallet.getSerialNo())
                    .eq(WalletAccount::getChainCoinNo, chainNativeCoin.getSerialNo()));
        }
        if (walletAccount == null) {
            log.warn("未找到商户:{} 的链上钱包账户，将回退到品牌 owner 配置", merchantNo);
            S11eProtocolProperties.BrandOwnerConfig brandOwner = s11eConfig.getBrandOwner();
            if (brandOwner == null
                    || StringUtils.isBlank(brandOwner.getAddress())
                    || StringUtils.isBlank(brandOwner.getPrivateKey())) {
                throw new BusinessException("WAAS_BRAND_OWNER_CONFIG_MISSING",
                        "品牌 owner 配置缺失，无法构建链上请求");
            }
            WalletAccount fallback = new WalletAccount();
            fallback.setAddress(brandOwner.getAddress());
            fallback.setPrivateKey(brandOwner.getPrivateKey());
            return fallback;
        }
        log.debug("查询商户:{} 对应钱包账户: {}", merchantNo, walletAccount);
        return walletAccount;
    }

    /**
     * 通过DID信息对数据签名
     * @param requestMap 请求参数，包含：did（DID标识）、data（要签名的数据）
     * @return 返回包含签名结果的Map
     */
    @ShenyuDubboClient("/signData")
    @ApiDoc(desc = "signData")
    @Override
    public Map<String, Object> signData(Map<String, Object> requestMap) throws Exception {
        Map<String, Object> result = new HashMap<>();
        
        // 获取请求参数
        String did = MapUtils.getString(requestMap, "did");
        String signData = MapUtils.getString(requestMap, "signData");

        // 从数据库查询DID档案信息
        LambdaQueryWrapper<DidProfile> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DidProfile::getDid, did);
        DidProfile didProfile = didProfileMapper.selectOne(queryWrapper);

        String keyDataJson = didProfile.getDidKeyData();

        // 从keyDataJson解析出密钥信息
        String signatureBase64 = DefaultTrustedDataSpaceConnector.signData(didProfile.getDid(), FIXED_ENCRYPTION_SALT, keyDataJson, signData);

        // 返回签名结果
        result.put("did", did);
        result.put("signData", signData);
        result.put("sign", signatureBase64);

        log.info("DID签名成功，DID: {}, 数据长度: {}", did, signData.length());
        return result;
    }

    /**
     * 通过DID信息对签名的数据验证签名
     * @param requestMap 请求参数，包含：did（DID标识）、data（原始数据）、signature（Base64编码的签名）
     * @return 返回包含验证结果的Map
     */
    @ShenyuDubboClient("/verifySign")
    @ApiDoc(desc = "verifySign")
    @Override
    public Map<String, Object> verifySign(Map<String, Object> requestMap) throws Exception {
        Map<String, Object> result = new HashMap<>();
        
        // 获取请求参数
        String did = MapUtils.getString(requestMap, "did");
        String signData = MapUtils.getString(requestMap, "signData");
        String sign = MapUtils.getString(requestMap, "sign");

        // 从数据库查询DID档案信息
        LambdaQueryWrapper<DidProfile> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DidProfile::getDid, did);
        DidProfile didProfile = didProfileMapper.selectOne(queryWrapper);
        String keyDataJson = didProfile.getDidKeyData();

        // 从keyDataJson解析出公钥（验证签名只需要公钥）
        Boolean isValid = DefaultTrustedDataSpaceConnector.verifySign(didProfile.getDid(), FIXED_ENCRYPTION_SALT, keyDataJson, signData,  sign);

        // 返回验证结果
        result.put("did", did);
        result.put("signData", signData);
        result.put("sign", sign);
        result.put("valid", isValid);

        log.info("DID签名验证完成，DID: {}, 验证结果: {}", did, isValid);
        return result;
    }

    @ShenyuDubboClient("/getPageList")
    @ApiDoc(desc = "getPageList")
    @Override
    public IPage<?> getPageList(Map<String, Object> requestMap) {
        LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
        String tenantId = loginUser.getTenantId();
        Object paginationObj =  requestMap.get("pagination");
        me.flyray.bsin.server.utils.Pagination pagination = new Pagination();
        BeanUtil.copyProperties(paginationObj,pagination);
        Page<DidProfile> page =
                new Page<>(pagination.getPageNum(), pagination.getPageSize());
        LambdaQueryWrapper<DidProfile> warapper = new LambdaQueryWrapper<>();
        warapper.orderByDesc(DidProfile::getCreateTime);
        warapper.eq(DidProfile::getTenantId, tenantId);
//        warapper.eq(
//                ObjectUtil.isNotNull(bizRoleTypeNo), DidProfile::getBizRoleTypeNo, bizRoleTypeNo);
        IPage<DidProfile> pageList = didProfileMapper.selectPage(page, warapper);
        return pageList;
    }


    /**
     * 基于DID查询用户的身份详情
     * @param requestMap
     */
    @ShenyuDubboClient("/getDetail")
    @ApiDoc(desc = "getDetail")
    @Override
    public DidProfile getDetail(Map<String, Object> requestMap) {
        String did = MapUtils.getString(requestMap, "did");
        String serialNo = MapUtils.getString(requestMap, "serialNo");
        String bizRoleTypeNo = MapUtils.getString(requestMap, "bizRoleTypeNo");
        String tenantId = MapUtils.getString(requestMap, "tenantId");
        
        LambdaQueryWrapper<DidProfile> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(DidProfile::getCreateTime);
        
        // 支持多种查询方式：按did、serialNo或bizRoleTypeNo查询
        wrapper.eq(ObjectUtil.isNotNull(did), DidProfile::getDid, did);
        wrapper.eq(ObjectUtil.isNotNull(serialNo), DidProfile::getSerialNo, serialNo);
        wrapper.eq(ObjectUtil.isNotNull(bizRoleTypeNo), DidProfile::getBizRoleTypeNo, bizRoleTypeNo);
        wrapper.eq(ObjectUtil.isNotNull(tenantId), DidProfile::getTenantId, tenantId);
        
        DidProfile customerProfile = didProfileMapper.selectOne(wrapper);
        return customerProfile;
    }

    private String maskSensitive(String value, int visibleTail) {
        if (value == null || value.length() <= visibleTail) {
            return value;
        }
        int maskLength = value.length() - visibleTail;
        StringBuilder sb = new StringBuilder(value.length());
        for (int i = 0; i < maskLength; i++) {
            sb.append('*');
        }
        sb.append(value.substring(maskLength));
        return sb.toString();
    }

}
